package com.talent.core.protocol.mqtt.store;

import com.talent.core.protocol.mqtt.TlMqttSession;
import com.talent.core.protocol.mqtt.model.entity.TlSubClient;
import com.talent.core.protocol.mqtt.model.entity.TlMessage;
import com.talent.core.protocol.mqtt.model.request.TlMqttPubRecReq;
import com.talent.core.protocol.mqtt.model.request.TlMqttPublishReq;

import java.util.List;
import java.util.Objects;

/**
 * @ClassName：IMqttStroe
 * @Author: hszhou
 * @Date: 2024/12/25 13:33
 * @Description: mqtt的相关数据存储
 */
public interface IMqttStore {


    /**
     * 储存订阅主题的客户端
     * @param client
     */
    void putSubClient(TlSubClient client);


    /**
     * 根据主题获取到订阅的客户端
     * @param topic
     * @return
     */
    List<TlSubClient> getSubClientByTopic(String topic);


    /**
     * 根据主题和qos获取到订阅的客户端
     * @param topic
     * @param qos
     * @return
     */
    List<TlSubClient> getSubClientByTopicAndQos(String topic, int qos);


    /**
     * 根据topic移除已经订阅的主题的客户端
     * @param topic
     */
    void removeSubClientByTopic(String topic,String clientId);


    /**
     * 保存客户端与对应的会哈
     * @param clientId
     * @param session
     */
    void putSession(String clientId, TlMqttSession session);

    /**
     * 根据客户端id获取session
     * @param clientId
     * @return
     */
    TlMqttSession getSessionByClientId(String clientId);


    /**
     * 移除会话
     * @param clientId
     * @return
     */
    TlMqttSession removeSessionByClientId(String clientId);


    /**
     * 通过主题获取到该主题的保留消息
     * @param topic
     * @return
     */
    TlMqttPublishReq getRetainMessageByTopic(String topic);


    TlMessage putRetainMessage(String topic, TlMessage req);


    /**
     * 存储本地消息
     * @param messageId
     * @param topic
     */
    void brokerStoreMsg(int messageId,TlMqttPublishReq req);

    /**
     * 移除本地消息
     * @param messageId
     */
    void removeStoreMsg(int messageId);


    /**
     * 根据消息ID获取哪一个主题
     * @param messageId
     * @return
     */
    TlMqttPublishReq getStoreMsg(int messageId);

    void storePubRec(int messageId, TlMqttPubRecReq req);

    void removePubRec(int messageId);

    TlMqttPubRecReq getPubRec(int messageId);



    /**
     *获取消息ID
     * @return
     */
    Integer getMessageId();


    /**
     * 判断是否pub的主题是否匹配订阅的主题
     * @param pub 发布主题
     * @param sub 订阅主题 - topicFilter
     * @return true if pub match sub
     */
    default boolean match(String pub, String sub) {
        if (Objects.equals(pub, sub)) {
            return true;
        }
        if (!sub.contains("#") && !sub.contains("+")) {
            return false;
        }

        boolean result = true;
        String[] pubs = pub.split("/");
        String[] subs = sub.split("/");
        int pubsLen = pubs.length;
        int subsLen = subs.length;
        if (pubsLen >= subsLen) {
            // 发布主题层级高于订阅层级
            for (int i = 0; i < pubsLen; i++) {
                String pubStr = pubs[i];
                String subStr = subs[i];
                if ("#".equals(subStr)) {
                    break;
                }
                if ("+".equals(subStr)) {
                    if (i == subsLen - 1) {
                        if (pubsLen != subsLen) {
                            result = false;
                        }
                        break;
                    }

                    continue;
                }
                if (!Objects.equals(pubStr, subStr)) {
                    result = false;
                    break;
                }

                // 有效长度匹配完成，后续无法匹配
                if (i == subsLen - 1) {
                    if (pubsLen != subsLen) {
                        result = false;
                    }
                    break;
                }
            }
        } else {
            if (sub.endsWith("#") && subsLen == pubsLen + 1) {
                // 这里只需要比较 pubsLen 的字符即可
                for (int i = 0; i < pubsLen; i++) {
                    String pubStr = pubs[i];
                    String subStr = subs[i];
                    if ("+".equals(subStr)) {
                        continue;
                    }
                    if (!Objects.equals(pubStr, subStr)) {
                        result = false;
                        break;
                    }
                }
            } else {
                return false;
            }
        }

        return result;
    }


}
